﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ufida.u9.ait.openapi.utils;
using UFIDA.U9.Base.UserRole;
using UFIDA.U9.CBO.HR.Department;
using UFIDA.U9.CBO.HR.Operator;
using UFIDA.U9.CBO.MFG.CostElement;
using UFIDA.U9.CBO.Pub.Controller;
using UFIDA.U9.CBO.SCM.Item;
using UFIDA.U9.CBO.SCM.ProjectTask;
using UFIDA.U9.CBO.SCM.Warehouse;
using UFIDA.U9.ER.ERBP;
using UFIDA.U9.ISV.MO.Proxy;
using UFIDA.U9.ISV.MO;
using UFIDA.U9.MO.Issue;
using UFIDA.U9.MO.MO;
using UFIDA.U9.PM.PM_Util;
using UFIDA.U9.SM.DealerSO;
using UFSoft.UBF.Business;
using UFIDA.U9.Base;
using UFIDA.U9.CBO.MFG.Enums;
using System.Reflection.Emit;

namespace ufida.u9.ait.openapi
{
    internal class IssueBase
    {
        public static IssueDoc ApproveDocEx(DocDTOData dto,IssueDoc doc)
        {
            if (!String.IsNullOrEmpty(dto.DocDate))
            {
                //修改日期
                using (ISession session = Session.Open())
                {
                    doc.BusinessDate = DateTime.Parse(dto.DocDate);//单据日期
                    doc.BusinessCreatedOn = doc.BusinessDate;//确认日期
                    doc.IssueItemOn = doc.BusinessDate;//发料确认日期
                    foreach(var line in doc.IssueDocLines)
                    {
                        line.ActualIssueDate = doc.BusinessDate;//实发日期
                    }

                    session.Commit();
                }
            }
            return ApproveDoc(doc);
        }
        /// <summary>
        /// 审核
        /// </summary>
        /// <param name="doc"></param>
        /// <returns></returns>
        public static IssueDoc ApproveDoc(IssueDoc doc)
        {
            doc = doc.Key.GetEntity();
            ApproveIssueDoc4ExternalSrv sv = new ApproveIssueDoc4ExternalSrv();
            sv.DocNoList = new List<ApproveIssueDoc4ExternalDTO>()
            {
                new ApproveIssueDoc4ExternalDTO()
                {
                    DocNo = doc.DocNo,
                    OperateType=true,//true=审核,false=弃审
                }
            };
            sv.IsNotNewTransaction = true;//避免服务里面再次启用事务
            List<ApproveIssueDoc4ExternalDTO> rets = sv.Do();
            //返回校验
            if (rets.Count > 0)
            {
                if (!rets[0].IsSucceed)
                {
                    throw new Exception(rets[0].ErrorMsg);
                }
            }
            return doc;
        }
        /// <summary>
        /// 弃审
        /// </summary>
        /// <param name="doc"></param>
        /// <returns></returns>
        public static IssueDoc UnApproveDoc(IssueDoc doc)
        {
            doc = doc.Key.GetEntity();
            ApproveIssueDoc4ExternalSrv sv = new ApproveIssueDoc4ExternalSrv();
            sv.DocNoList = new List<ApproveIssueDoc4ExternalDTO>()
            {
                new ApproveIssueDoc4ExternalDTO()
                {
                    DocNo = doc.DocNo,
                    OperateType=false,//true=审核,false=弃审
                }
            };
            sv.IsNotNewTransaction = true;//避免服务里面再次启用事务
            List<ApproveIssueDoc4ExternalDTO> rets = sv.Do();
            //返回校验
            if (rets.Count > 0)
            {
                if (!rets[0].IsSucceed)
                {
                    throw new Exception(rets[0].ErrorMsg);
                }
            }
            return doc;
        }

        public static IssueDoc CreateDoc(CopyOfIssueDTOData dto)
        {
            IssueDoc doc;
            using (ISession session = Session.Open())
            {
                doc = CreateHead(dto);
                CreateLine(doc, dto);

                session.Commit();
            }
            return doc;
        }

        private static void CreateLine(IssueDoc doc, CopyOfIssueDTOData dto)
        {
            foreach (var linedto in dto.PickListDTOs)
            {
                //赋值
                IssueDocLine line = IssueDocLine.Create(doc);
                LineDefault(doc, linedto, line);
                //数量
                LineQty(linedto, line);
                //来源单据
                LineSrc(doc, linedto, line);
            }
        }

        private static void LineSrc(IssueDoc doc, CopyOfPickListDTOData linedto, IssueDocLine line)
        {
            //收发类型=退料
            if (doc.IssueType == UFIDA.U9.MO.Enums.IssueTypeEnum.Withdrawal)
            {
                if (linedto.SrcIssueDoc == null)
                    throw new Exception($"IssueType为退料,来源单据[SrcIssueDoc]为空");
            }
            //来源单据处理
            if (linedto.SrcIssueDoc != null)
            {
                //MOSrcDocType
                if (linedto.SrcIssueDoc.MOSrcDocType == 22)
                {
                    //来源单据=领料单
                    //退料处理
                    if (doc.IssueType != UFIDA.U9.MO.Enums.IssueTypeEnum.Withdrawal)
                        throw new Exception($"来源单据=领料单,IssueType必须为退料");
                    IssueDocLine srcline = EntityUtils.GetEntityByPath<IssueDocLine>($"LineNum={linedto.SrcIssueDoc.SrcDocLineNo} and IssueDoc.DocNo='{linedto.SrcIssueDoc.SrcDocNo}'");

                    if (srcline.Item.Code != line.Item.Code)
                        throw new Exception($"来源物料[{srcline.ItemInfo.ItemCode}]与传入物料[{line.Item.Code}]不同");
                    FieldFromIssueDoc(line, srcline);
                }
                else if (linedto.SrcIssueDoc.MOSrcDocType == 18)
                {
                    //来源单据=生产订单备料
                    MOPickList pickList = EntityUtils.GetEntityByPath<MOPickList>($"DocLineNO={linedto.SrcIssueDoc.SrcDocLineNo} and MO.DocNo='{linedto.SrcIssueDoc.SrcDocNo}'");
                    if (doc.IssueType == UFIDA.U9.MO.Enums.IssueTypeEnum.Withdrawal)
                    {
                        //来源单据=生产订单备料
                        //领料退料处理
                        //界面上选择备料退料,还会弹出领料单进行选择
                        //查找可退料的领料单,条件:来源备料相同,收发类型=发料/超额,状态=关闭,按照ID升序
                        string path = $"MOPick={pickList.ID} and IssueDoc.IssueType in (0,3) and IssueDoc.DocState in (2) order by ID";
                        IssueDocLine.EntityList issueList = IssueDocLine.Finder.FindAll(path);
                        IssueDocLine srcline = null;
                        foreach (var issueline in issueList)
                        {
                            //可退数量=实发数量-累计退料数量
                            decimal ktsl = issueline.IssuedQty - issueline.RecedeIssuedQty;
                            if (ktsl <= 0 || ktsl < linedto.IssuedQty)
                                continue;
                            //if (ktsl < linedto.IssuedQty)
                            //    throw new Exception($"物料[{linedto.Item.Code}]可退数量最大为[{ktsl}],当前退料数量[{linedto.IssuedQty}]");
                            srcline = issueline;
                            break;
                        }
                        if (srcline == null)
                            throw new Exception($"备料没有匹配的领料单,生产订单[{linedto.SrcIssueDoc.SrcDocNo}],备料行[{linedto.SrcIssueDoc.SrcDocLineNo}]");
                        //校验
                        if (srcline.Item.Code != line.Item.Code)
                            throw new Exception($"来源物料[{srcline.Item.Code}]与传入物料[{line.Item.Code}]不同");
                        //赋值
                        FieldFromIssueDoc(line, srcline);
                    }
                    else if (doc.IssueType == UFIDA.U9.MO.Enums.IssueTypeEnum.Issue)
                    {
                        //来源单据=生产订单备料
                        //生产领料处理
                        //校验
                        if (pickList.ItemMaster.Code != line.Item.Code)
                            throw new Exception($"来源物料[{pickList.ItemMaster.Code}]与传入物料[{line.Item.Code}]不同");
                        if (pickList.MO.isCanceled())
                            throw new Exception($"生产订单[{pickList.MO.DocNo}]已经终止!");
                        if (pickList.MO.IsHold())
                            throw new Exception($"生产订单[{pickList.MO.DocNo}]已经挂起!");

                        //生产领料赋值
                        FieldFromMO(linedto, line, pickList);
                    }
                }
                else if (linedto.SrcIssueDoc.MOSrcDocType == 14)
                {
                    //来源单据=生产订单,无备料领料
                    MO mo = EntityUtils.GetEntityByPath<MO>($"DocNo='{linedto.SrcIssueDoc.SrcDocNo}'");
                    //校验
                    if (mo.isCanceled())
                        throw new Exception($"生产订单[{mo.DocNo}]已经终止!");
                    if (mo.IsHold())
                        throw new Exception($"生产订单[{mo.DocNo}]已经挂起!");

                    FieldFromMO(line, mo);
                }
            }
        }

        private static void LineDefault(IssueDoc doc, CopyOfPickListDTOData linedto, IssueDocLine line)
        {
            //行号
            if (linedto.LineNum > 0)
            {
                line.LineNum = linedto.LineNum;
            }
            else
            {
                line.LineNum = doc.IssueDocLines.Count * 10;
            }
            //组织
            line.OwnerOrg = Context.LoginOrg;
            line.BenifitOrg = Context.LoginOrg;
            //物料
            if (linedto.Item == null)
                throw new Exception("料品[Item]为空");
            ItemMaster item = EntityUtils.GetEntityByCode<ItemMaster>(linedto.Item);//料品
            line.Item = item;

            //等级
            if (linedto.Grade >= 0)
            {
                line.Grade = GradeEnum.GetFromValue(linedto.Grade); //等级
                //if (String.IsNullOrEmpty(line.Grade.Name))
                //    throw new Exception("等级传入错误");
            }
            if (linedto.Element >= 0)
            {
                line.Element = ElementEnum.GetFromValue(linedto.Element); //成分
            }

            //部门
            if (linedto.IssueDept == null)
            {
                line.IssueDept = doc.HandleDept;
            }
            else
            {
                line.IssueDept = EntityUtils.GetEntityByCode<Department>(linedto.IssueDept);
            }
            line.PlanIssueDate = doc.BusinessCreatedOn;
            line.ActualIssueDate = doc.BusinessCreatedOn;//实发时间
            //其他赋值
            //if (linedto.IssueWh == null) throw new Exception("存储地点 必填");
            //开立单据允许仓库为空
            if (linedto.IssueWh != null && !string.IsNullOrEmpty(linedto.IssueWh.Code))
            {
                line.Wh = EntityUtils.GetEntityByCode<Warehouse>(linedto.IssueWh);//仓库
                if (linedto.Bin != null && !string.IsNullOrEmpty(linedto.Bin.Code))
                {
                    line.Bin = EntityUtils.GetBin(linedto.IssueWh.Code, linedto.Bin.Code);//库位
                }
            }

            if (linedto.LotMaster != null) line.LotNo = linedto.LotMaster.Code;//批号
            if (!string.IsNullOrEmpty(linedto.LotDisableDate))
                line.LotDisableDate = DateTime.Parse(linedto.LotDisableDate);//失效日期
            if (linedto.StorageType > -1)
            {
                line.StorageType = UFIDA.U9.CBO.Enums.StorageTypeEnum.GetFromValue(linedto.StorageType);//存储类型
            }
            else
            {
                line.StorageType = UFIDA.U9.CBO.Enums.StorageTypeEnum.GetFromValue(4);//存储类型
            }
            line.OpNum = "10"; //工序号
            line.Currency = item.CostCurrency;
            if (linedto.Project != null)
                line.Project = EntityUtils.GetEntityByCode<Project>(linedto.Project);//项目

            //扩展字段处理
            if (linedto.DescFlexField != null)
            {
                line.DescFlexField = new UFIDA.U9.Base.FlexField.DescFlexField.DescFlexSegments();
                DTOUtils.DTOPropCopy(linedto.DescFlexField, line.DescFlexField);
            }
        }

        private static void LineQty(CopyOfPickListDTOData linedto, IssueDocLine line)
        {
            //单位
            ItemMaster item = line.Item;
            line.WhUOM = item.InventoryUOM;//库存单位
            line.StoreBaseUOM = item.InventoryUOM.BaseUOM;
            line.IssueUOM = item.MaterialOutUOM;//领料单位
            line.IssueBaseUOM = item.MaterialOutUOM.BaseUOM;
            line.CoUOM = item.CostUOM;//成本单位
            line.CostBaseUOM = item.CostUOM.BaseUOM;
            //数量
            if (linedto.IssuedQty == 0) throw new Exception("IssuedQty为空");
            line.IssueQty = linedto.IssueQty > 0 ? linedto.IssueQty : linedto.IssuedQty;//应发数量
            line.IssuedQty = linedto.IssuedQty; //实发数量
            line.IssuedQtyByWhUOM = linedto.IssuedQty;//实发-库存
            line.IssuedQtyByCoUOM = linedto.IssuedQtyByCoUOM > 0 ? linedto.IssuedQtyByCoUOM : linedto.IssuedQty;//实发-成本
            //转化率
            line.IBUToCBURate = line.IssuedQtyByCoUOM / line.IssuedQtyByWhUOM;//库存-成本
            line.IBUToSBURate = 1;//发料-库存
            line.IUToIBURate = 1;//发料主-副
            line.SUToSBURate = 1;//库存主-副
            line.CUToCBURate = 1;//成本主-副
        }

        /// <summary>
        /// 来源备料的领料单
        /// </summary>
        /// <param name="linedto">领料行DTO</param>
        /// <param name="line">领料行</param>
        /// <param name="pickList">备料行</param>
        private static void FieldFromMO(CopyOfPickListDTOData linedto,IssueDocLine line, MOPickList pickList)
        {
            //来源
            line.MO = pickList.MO;
            line.MOPick = pickList;
            
            //应发数量 = 传入 或 备料实际用量-备料已发数量
            line.IssueQty = linedto.IssueQty > 0 ? linedto.IssueQty : pickList.ActualReqQty - pickList.IssuedQty;
            //其他
            line.ProductItem = pickList.MO.ItemMaster;
            line.PlanIssueDate = pickList.ActualIssueDate;
            line.ConsignProcessItemSrc = pickList.ConsignProcessItemSrc;
            line.IsCalcCost = true;
            line.CostField = pickList.MO.CostField;
            line.CostElement = pickList.CostElement;
            line.OpNum = pickList.OperationNum;//工序号
            //工作中心
            if(pickList.MO.MOOperations!=null&& pickList.MO.MOOperations.Count>0)
            {
                foreach(var op in pickList.MO.MOOperations)
                {
                    if (op.OperationNum == line.OpNum)
                    {
                        line.WorkCenter = op.WorkCenter;
                        break;
                    }
                }
            }
        }
        /// <summary>
        /// 无备料领料,来源MO
        /// </summary>
        /// <param name="line">领料单行</param>
        /// <param name="mo">MO</param>
        private static void FieldFromMO(IssueDocLine line, MO mo)
        {
            //来源
            line.MO = mo;
            //数量,单价,成本

            //其他
            line.ProductItem = mo.ItemMaster;
            line.PlanIssueDate = DateTime.Now;
            line.ConsignProcessItemSrc = ConsignProcessItemSrcEnum.IssuedByConsignee;
            line.CostField = mo.CostField;
            line.CostElement = EntityUtils.GetEntityByCode<CostElement>("No101");

        }
        private static void FieldFromIssueDoc(IssueDocLine line, IssueDocLine srcline)
        {
            //来源
            line.MO = srcline.MO;
            line.BenifitMO = srcline.MO;
            line.MOPick = srcline.MOPick;
            line.SourceIssueDocLine = srcline;
            //数量,单价,成本,金额
            line.Price = srcline.Price;
            line.CostAmt = line.Price * line.IssuedQty;
            line.CostField = srcline.CostField;
            line.CostElement = srcline.CostElement;
            //line.IssueQty = srcline.IssueQty - srcline.RecedeIssuedQty;
            //其他
            line.ProductItem = srcline.ProductItem;
            line.PlanIssueDate = srcline.PlanIssueDate;
            line.ConsignProcessItemSrc = srcline.ConsignProcessItemSrc;
            line.RecedeReason = UFIDA.U9.MO.Enums.RecedeReasonEnum.PullReason;
            line.OpNum = srcline.OpNum;//工序号

        }

        private static IssueDoc CreateHead(CopyOfIssueDTOData dto)
        {
            //默认值
            IssueDoc doc = IssueDoc.Create();
            //doc.DocNo = dto.DocNo;
            //单据类型
            IssueDocType doctype = EntityUtils.GetEntityByCode<IssueDocType>(dto.DocType.Code);
            doc.IssueDocType = doctype;
            //收发类型
            //Excess	超额	 3
            //Issue	发料	 0
            //MoveItem	挪料 2
            //Withdrawal	退料 1
            doc.IssueType = UFIDA.U9.MO.Enums.IssueTypeEnum.GetFromValue(dto.IssueType);
            //日期
            if (string.IsNullOrEmpty(dto.BusinessDate)) throw new Exception("业务日期必填");
            doc.BusinessDate = DateTime.Parse(dto.BusinessDate);
            doc.IssueItemOn = doc.BusinessDate;
            doc.IssueItemBy = Context.LoginUser;
            if (!String.IsNullOrEmpty(dto.BusinessCreatedOn))
                doc.BusinessCreatedOn = DateTime.Parse(dto.BusinessCreatedOn);
            else
                doc.BusinessCreatedOn = doc.BusinessDate;
            //组织
            doc.Org = Context.LoginOrg;
            doc.IssueOrg = Context.LoginOrg;
            //其他
            doc.WorkFlowID = Guid.Empty;
            doc.StateMachineID = Guid.Empty;
            doc.BusinessCreatedBy = User.Finder.FindByID(Context.LoginUserID);
            doc.Cancel.CancelDate = DateTime.MinValue;
            
            doc.HandleDept = EntityUtils.GetEntityByCode<Department>(dto.Dept);//部门
            doc.HandlePerson = EntityUtils.GetEntityByCode<Operators>(dto.Employee);//业务员
            if (doc.HandlePerson != null)
            {
                doc.HandleDept = doc.HandlePerson.Dept;
            }

            //扩展字段处理
            if (dto.DescFlexField != null)
            {
                doc.DescFlexField = new UFIDA.U9.Base.FlexField.DescFlexField.DescFlexSegments();
                DTOUtils.DTOPropCopy(dto.DescFlexField, doc.DescFlexField);
            }
            
            return doc;
        }
    }
}
